{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "7b5ec0ee-ea15-48e7-b6c4-648e500ef7f2",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n"
     ]
    }
   ],
   "source": [
    "# 获取Deepseek API Key\n",
    "\n",
    "import os\n",
    "\n",
    "api_key = os.getenv('DEEPSEEK_API_KEY')\n",
    "if api_key is None:\n",
    "    api_key = ''\n",
    "print(api_key)\n",
    "\n",
    "# 设置清华代理\n",
    "\n",
    "os.environ['HF_ENDPOINT'] = 'https://hf-mirror.com'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "da329d31-1c6e-45d6-b8ea-5a14c27bd219",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "72\n"
     ]
    }
   ],
   "source": [
    "# 准备知识数据\n",
    "\n",
    "from glob import glob\n",
    "\n",
    "text_lines = []\n",
    "\n",
    "for file_path in glob('milvus_docs/en/faq/*.md', recursive=True):\n",
    "    with open(file_path, 'r') as file:\n",
    "        text_line = file.read()\n",
    "    text_lines += text_line.split('# ')\n",
    "\n",
    "print(len(text_lines))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "2ec294a0-6559-4e16-ba49-d97cedad9e21",
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/miniconda3/envs/deepseek/lib/python3.13/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n",
      "  from .autonotebook import tqdm as notebook_tqdm\n",
      "Error while downloading from https://cdn-lfs.hf-mirror.com/repos/7d/e2/7de2d395a72b821bd90ee57675be2bf014b99d44d8d6c6dbac2cf72b183e2d64/a173875cdc1ed10fc67ed1d4900d10b5414bd20052eb33785ffa1cad0162afb8?response-content-disposition=inline%3B+filename*%3DUTF-8%27%27model.onnx%3B+filename%3D%22model.onnx%22%3B&Expires=1749288930&Policy=eyJTdGF0ZW1lbnQiOlt7IkNvbmRpdGlvbiI6eyJEYXRlTGVzc1RoYW4iOnsiQVdTOkVwb2NoVGltZSI6MTc0OTI4ODkzMH19LCJSZXNvdXJjZSI6Imh0dHBzOi8vY2RuLWxmcy5oZi5jby9yZXBvcy83ZC9lMi83ZGUyZDM5NWE3MmI4MjFiZDkwZWU1NzY3NWJlMmJmMDE0Yjk5ZDQ0ZDhkNmM2ZGJhYzJjZjcyYjE4M2UyZDY0L2ExNzM4NzVjZGMxZWQxMGZjNjdlZDFkNDkwMGQxMGI1NDE0YmQyMDA1MmViMzM3ODVmZmExY2FkMDE2MmFmYjg%7EcmVzcG9uc2UtY29udGVudC1kaXNwb3NpdGlvbj0qIn1dfQ__&Signature=cVQ32bBkzIbB3ZKfJ9TAkt1xqVLI0wxsJuW17ev7ZrHOFuX6KTel9%7ElMcLHU0gtF9GboiZaFtI3NUapby38xEVwWhO0ekSTgz0KtKsUqBCH8-u7v4SO9fKsWcfTD02LxP536HD0RKK7syqKyO9u63UlwxmJVu1%7EYT6HfMOwPZ06%7EiQU8eNHOKwbKYH7EQSA7swjtQYDRAPHLBRr9-dW6d1Phv4ZHiFknjA%7EVuM8EjHrHXoSzW1Nz4LPszc6CL-gx45604gi%7ESX6cLWSHyLgKtlzeGM5n21bIPuimQpgciGT-YGpwkSN4jaUnJvn2dsOLDMnbvjuWIS4Oyq6OM4AoDg__&Key-Pair-Id=K3RPWS32NSSJCE: HTTPSConnectionPool(host='cdn-lfs.hf-mirror.com', port=443): Read timed out.\n",
      "Trying to resume download...\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "768\n"
     ]
    }
   ],
   "source": [
    "# 准备Embedding模型\n",
    "\n",
    "from pymilvus import model as milvus_model\n",
    "\n",
    "embedding_model = milvus_model.DefaultEmbeddingFunction()\n",
    "test_embdding = embedding_model.encode_queries(['This is a test'])[0]\n",
    "embedding_dim = len(test_embdding)\n",
    "\n",
    "print(embedding_dim)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "2de665fa-1588-466b-b351-3977c8a629ca",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Creating embeddings: 100%|██████████| 72/72 [00:00<00:00, 338553.69it/s]\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "{'insert_count': 72, 'ids': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71], 'cost': 0}"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 将知识数据加载至Milvus数据库\n",
    "\n",
    "from pymilvus import MilvusClient\n",
    "from tqdm import tqdm\n",
    "\n",
    "my_collection = 'faq_rag_collection'\n",
    "\n",
    "milvus_client = MilvusClient(uri='./milvus_demo.db')\n",
    "\n",
    "if milvus_client.has_collection(my_collection):\n",
    "    milvus_client.drop_collection(my_collection)\n",
    "\n",
    "milvus_client.create_collection(\n",
    "    collection_name=my_collection,\n",
    "    dimension=embedding_dim,\n",
    "    metric_type='IP',\n",
    "    consistency_level='Strong'\n",
    ")\n",
    "\n",
    "data = []\n",
    "\n",
    "doc_embeddings = embedding_model.encode_documents(text_lines)\n",
    "for i, line in enumerate(tqdm(text_lines, desc='Creating embeddings')):\n",
    "    data.append({'id':i, 'vector': doc_embeddings[i], 'text': line})\n",
    "\n",
    "milvus_client.insert(collection_name=my_collection, data=data)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "c8bb2f63-920f-4f12-a823-de91ab0aefa9",
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[\n",
      "    [\n",
      "        \" Where does Milvus store data?\\n\\nMilvus deals with two types of data, inserted data and metadata. \\n\\nInserted data, including vector data, scalar data, and collection-specific schema, are stored in persistent storage as incremental log. Milvus supports multiple object storage backends, including [MinIO](https://min.io/), [AWS S3](https://aws.amazon.com/s3/?nc1=h_ls), [Google Cloud Storage](https://cloud.google.com/storage?hl=en#object-storage-for-companies-of-all-sizes) (GCS), [Azure Blob Storage](https://azure.microsoft.com/en-us/products/storage/blobs), [Alibaba Cloud OSS](https://www.alibabacloud.com/product/object-storage-service), and [Tencent Cloud Object Storage](https://www.tencentcloud.com/products/cos) (COS).\\n\\nMetadata are generated within Milvus. Each Milvus module has its own metadata that are stored in etcd.\\n\\n###\",\n",
      "        0.65726637840271\n",
      "    ],\n",
      "    [\n",
      "        \"How does Milvus flush data?\\n\\nMilvus returns success when inserted data are loaded to the message queue. However, the data are not yet flushed to the disk. Then Milvus' data node writes the data in the message queue to persistent storage as incremental logs. If `flush()` is called, the data node is forced to write all data in the message queue to persistent storage immediately.\\n\\n###\",\n",
      "        0.6312144994735718\n",
      "    ],\n",
      "    [\n",
      "        \"How does Milvus handle vector data types and precision?\\n\\nMilvus supports Binary, Float32, Float16, and BFloat16 vector types.\\n\\n- Binary vectors: Store binary data as sequences of 0s and 1s, used in image processing and information retrieval.\\n- Float32 vectors: Default storage with a precision of about 7 decimal digits. Even Float64 values are stored with Float32 precision, leading to potential precision loss upon retrieval.\\n- Float16 and BFloat16 vectors: Offer reduced precision and memory usage. Float16 is suitable for applications with limited bandwidth and storage, while BFloat16 balances range and efficiency, commonly used in deep learning to reduce computational requirements without significantly impacting accuracy.\\n\\n###\",\n",
      "        0.6115781664848328\n",
      "    ]\n",
      "]\n"
     ]
    }
   ],
   "source": [
    "# 查询Milvus数据库\n",
    "\n",
    "import json\n",
    "\n",
    "question = 'How is data stored in milvus?'\n",
    "\n",
    "search_res = milvus_client.search(\n",
    "    collection_name=my_collection,\n",
    "    data=embedding_model.encode_queries([question]),\n",
    "    limit=3,\n",
    "    search_params={'metric_type': 'IP', 'params': {}},\n",
    "    output_fields=['text']\n",
    ")\n",
    "\n",
    "retrieved_lines = [(res['entity']['text'], res['distance']) for res in search_res[0]]\n",
    "\n",
    "print(json.dumps(retrieved_lines, indent=4))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "2fb53643-6f33-42c4-9ebf-aeba70e8e302",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Milvus stores data in two main categories: inserted data and metadata.\n",
      "\n",
      "1. **Inserted Data**:\n",
      "   - Includes vector data, scalar data, and collection-specific schema.\n",
      "   - Stored as incremental logs in persistent storage.\n",
      "   - Supports multiple object storage backends such as MinIO, AWS S3, Google Cloud Storage (GCS), Azure Blob Storage, Alibaba Cloud OSS, and Tencent Cloud Object Storage (COS).\n",
      "\n",
      "2. **Metadata**:\n",
      "   - Generated internally by Milvus.\n",
      "   - Each Milvus module has its own metadata stored in etcd.\n",
      "\n",
      "Additionally, Milvus flushes data to disk by first loading inserted data into a message queue (returning success at this stage). The data node then writes this data to persistent storage as incremental logs. Calling `flush()` forces immediate writing of all queued data to disk.\n",
      "\n",
      "<translated>\n",
      "Milvus以两种主要类型存储数据：插入数据和元数据。\n",
      "\n",
      "1. **插入数据**：\n",
      "   - 包括向量数据、标量数据和集合特定模式。\n",
      "   - 以增量日志形式存储在持久化存储中。\n",
      "   - 支持多种对象存储后端，如MinIO、AWS S3、Google云存储(GCS)、Azure Blob存储、阿里云OSS和腾讯云对象存储(COS)。\n",
      "\n",
      "2. **元数据**：\n",
      "   - 由Milvus内部生成。\n",
      "   - 每个Milvus模块的元数据存储在etcd中。\n",
      "\n",
      "此外，Milvus通过先将插入数据加载到消息队列（此时返回成功）来刷新数据到磁盘。数据节点随后将这些数据作为增量日志写入持久存储。调用`flush()`会强制立即将所有队列中的数据写入磁盘。\n",
      "</translated>\n"
     ]
    }
   ],
   "source": [
    "# 结合Deepseek完成RAG查询\n",
    "\n",
    "from openai import OpenAI\n",
    "\n",
    "deepseek_client = OpenAI(\n",
    "    api_key=api_key,\n",
    "    base_url='https://api.deepseek.com/v1'\n",
    ")\n",
    "\n",
    "SYSTEM_PROMPT = \"\"\"\n",
    "你是一个AI助手，你能够从提供的上下文段落片段中找到问题的答案。\n",
    "\"\"\"\n",
    "\n",
    "context = '\\n'.join([line_with_distance[0] for line_with_distance in retrieved_lines])\n",
    "\n",
    "USER_PROMPT = f\"\"\"\n",
    "请使用以下用<context>标签括起来的信息片段来回答用<question>标签括起来的问题，最后追加原始回答的中文翻译，并用<translated></translated>标签标注。\n",
    "<context>\n",
    "{context}\n",
    "</context>\n",
    "<question>\n",
    "{question}\n",
    "</question>\n",
    "<translated>\n",
    "</translated>\n",
    "\"\"\"\n",
    "\n",
    "response = deepseek_client.chat.completions.create(\n",
    "    model='deepseek-chat',\n",
    "    messages=[\n",
    "        {'role': 'system', 'content': SYSTEM_PROMPT},\n",
    "        {'role': 'user', 'content': USER_PROMPT}\n",
    "    ]\n",
    ")\n",
    "\n",
    "print(response.choices[0].message.content)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7b3ad2fc-75f3-4c1d-8bce-6f5424a34293",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.13.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
